﻿using System;
using System.Linq.Expressions;

namespace Mg.ExpressionParser
{
    internal class ExpressionParserProvider
    {
        private static readonly IExpressionParser[] Parsers = InitParsers();

        static IExpressionParser[] InitParsers()
        {
            var codes = Enum.GetValues(typeof(ExpressionTypeCode));
            var parsers = new IExpressionParser[codes.Length];

            foreach (ExpressionTypeCode code in codes)
            {
                if (code.ToString().EndsWith("Expression"))
                {
                    var type = Type.GetType(typeof(ExpressionParserProvider).Namespace + ".Parser." + code.ToString() + "Parser");
                    if (type != null)
                    {
                        parsers[(int)code] = (IExpressionParser)Activator.CreateInstance(type);
                    }
                }
            }
            return parsers;
        }


        private static ExpressionTypeCode GetParserCode(Expression expression)
        {
            if (expression == null)
            {
                return ExpressionTypeCode.Null;
            }

            if (expression is BinaryExpression)
            {
                return ExpressionTypeCode.BinaryExpression;
            }
            if (expression is BlockExpression)
            {
                return ExpressionTypeCode.BlockExpression;
            }
            if (expression is ConditionalExpression)
            {
                return ExpressionTypeCode.ConditionalExpression;
            }
            if (expression is ConstantExpression)
            {
                return ExpressionTypeCode.ConstantExpression;
            }
            if (expression is DebugInfoExpression)
            {
                return ExpressionTypeCode.DebugInfoExpression;
            }
            if (expression is DefaultExpression)
            {
                return ExpressionTypeCode.DefaultExpression;
            }
            if (expression is DynamicExpression)
            {
                return ExpressionTypeCode.DynamicExpression;
            }
            if (expression is GotoExpression)
            {
                return ExpressionTypeCode.GotoExpression;
            }
            if (expression is IndexExpression)
            {
                return ExpressionTypeCode.IndexExpression;
            }
            if (expression is InvocationExpression)
            {
                return ExpressionTypeCode.InvocationExpression;
            }
            if (expression is LabelExpression)
            {
                return ExpressionTypeCode.LabelExpression;
            }
            if (expression is LambdaExpression)
            {
                return ExpressionTypeCode.LambdaExpression;
            }
            if (expression is ListInitExpression)
            {
                return ExpressionTypeCode.ListInitExpression;
            }
            if (expression is LoopExpression)
            {
                return ExpressionTypeCode.LoopExpression;
            }
            if (expression is MemberExpression)
            {
                return ExpressionTypeCode.MemberExpression;
            }
            if (expression is MemberInitExpression)
            {
                return ExpressionTypeCode.MemberInitExpression;
            }
            if (expression is MethodCallExpression)
            {
                return ExpressionTypeCode.MethodCallExpression;
            }
            if (expression is NewArrayExpression)
            {
                return ExpressionTypeCode.NewArrayExpression;
            }
            if (expression is NewExpression)
            {
                return ExpressionTypeCode.NewExpression;
            }
            if (expression is ParameterExpression)
            {
                return ExpressionTypeCode.ParameterExpression;
            }
            if (expression is RuntimeVariablesExpression)
            {
                return ExpressionTypeCode.RuntimeVariablesExpression;
            }
            if (expression is SwitchExpression)
            {
                return ExpressionTypeCode.SwitchExpression;
            }
            if (expression is TryExpression)
            {
                return ExpressionTypeCode.TryExpression;
            }
            if (expression is TypeBinaryExpression)
            {
                return ExpressionTypeCode.TypeBinaryExpression;
            }
            if (expression is UnaryExpression)
            {
                return ExpressionTypeCode.UnaryExpression;
            }
            return ExpressionTypeCode.Unknown;
        }

        public static IExpressionParser GetParser(Expression expression)
        {
            ExpressionTypeCode cType = GetParserCode(expression);
            IExpressionParser parser = Parsers[(int)cType];

            if(parser == null)
            {
                if(cType == ExpressionTypeCode.Unknown )
                    throw new ArgumentException("未知的表达式类型", "expression");
                else if(cType == ExpressionTypeCode.Null)
                    throw new ArgumentNullException("expression", "表达式为空");
                else
                    throw new NotImplementedException("尚未实现" + cType + "的解析");
            }

            return parser;
        }


        public static void Update(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).Update(expression, sqlPack);
        }

        public static void Select(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).Select(expression, sqlPack);
        }

        public static void Join(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).Join(expression, sqlPack);
        }

        public static void Where(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).Where(expression, sqlPack);
        }

        public static void In(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).In(expression, sqlPack);
        }

        public static void GroupBy(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).GroupBy(expression, sqlPack);
        }

        public static void OrderBy(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).OrderBy(expression, sqlPack);
        }

        public static void Max(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).Max(expression, sqlPack);
        }

        public static void Min(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).Min(expression, sqlPack);
        }

        public static void Avg(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).Avg(expression, sqlPack);
        }

        public static void Count(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).Count(expression, sqlPack);
        }

        public static void Sum(Expression expression, SqlPack sqlPack)
        {
            GetParser(expression).Sum(expression, sqlPack);
        }

    }
}
